﻿using System;
using System.Collections.Generic;
using System.Linq;
using GCTrackableRace.Interfaces;
using GcTrackableRace.Entities;

namespace GcTrackableRace.ScoreCalculator.Rules
{
	public class AmountOfSpecificCountryMultipleVisitsRule: BaseRule, IRaceRule
	{
		public AmountOfSpecificCountryMultipleVisitsRule(string reportColumnName, string startDate, string endDate, string pointAllocation, 
			string keycodes, ILocationInfoLookup countryLookup)
			:base(reportColumnName, startDate, endDate, pointAllocation)
		{
			CountryLookup = countryLookup;

			AvailableCountries = keycodes.Split(new[] { ';', '|' }, StringSplitOptions.RemoveEmptyEntries).Select(k => k.Trim()).ToList();
		}

		private ILocationInfoLookup CountryLookup { get; set; }

		private IEnumerable<string> AvailableCountries { get; set; }

		protected override void SetRuleName()
		{
			RuleName = "Amount of specific country multiple visits rule";
		}

		public override void Process(ITrackable trackable, IEnumerable<ITrackableLog> trackableLogs)
		{
			var applicableLogs = (
				from log in trackableLogs
				where (
					(log.LogType == LogType.DroppedOff || log.LogType == LogType.Visited)
					&&
					log.Date >= StartDate &&
					log.Date <= EndDate
					)
				select log)
				.OrderBy(logs => logs.Date)
				.ThenBy(logs => logs.LogId)
				.ToList();

			var countries = new List<string>();

			var previousCountry = "";

			foreach (var log in applicableLogs)
			{
				var country = CountryLookup.GetCountryCodeUsingCoords(log.Latitude, log.Longitude);

				if(AvailableCountries.Contains(country) && previousCountry != country)
				{
					countries.Add(country);
				}

				previousCountry = country;
			}

			trackable.AddScore(new RuleScore(
				RuleName, 
				ReportColumnName,
				countries.Count,
				(int)(countries.Count * PointAllocation), 
				String.Join("|" , countries).Trim('|')));
		}
	}
}
